//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package api_coll_dao

import (
	"context"

	"atomgit.com/openlinksaas/api-server/dao/db_ns"
	"atomgit.com/openlinksaas/proto-gen-go.git/http_custom_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type HttpKeyValueDbItem struct {
	Id    string `bson:"id"`
	Key   string `bson:"key"`
	Value string `bson:"value"`
}

type UrlEncodeBodyDbItem struct {
	ParamList []HttpKeyValueDbItem `bson:"paramList"`
}

type MultiPartDbItem struct {
	Id     string `bson:"id"`
	Key    string `bson:"key"`
	Value  string `bson:"value"`
	IsFile bool   `bson:"isFile"`
}

type MultiPartBodyDbItem struct {
	PartList []MultiPartDbItem `bson:"partList"`
}

type ApiItemInfoDbItem struct {
	ApiItemId   string               `bson:"_id"`
	ApiItemName string               `bson:"apiItemName"`
	ApiCollId   string               `bson:"apiCollId"`
	GroupId     string               `bson:"groupId"`
	Method      string               `bson:"method"`
	Url         string               `bson:"url"`
	ParamList   []HttpKeyValueDbItem `bson:"paramList"`
	HeaderList  []HttpKeyValueDbItem `bson:"headerList"`
	BodyType    uint32               `bson:"bodyType"`
	ContentType string               `bson:"contentType"`

	TextBody      *string              `bson:"textBody"`
	UrlEncodeBody *UrlEncodeBodyDbItem `bson:"urlEncodeBody"`
	MultiPartBody *MultiPartBodyDbItem `bson:"multiPartBody"`

	TimeStamp int64 `bson:"timeStamp"`
}

func (item *ApiItemInfoDbItem) ToApiItemInfo() *http_custom_api.ApiItemInfo {
	paramList := []*http_custom_api.HttpKeyValue{}
	for _, p := range item.ParamList {
		paramList = append(paramList, &http_custom_api.HttpKeyValue{
			Id:    p.Id,
			Key:   p.Key,
			Value: p.Value,
		})
	}
	headerList := []*http_custom_api.HttpKeyValue{}
	for _, p := range item.HeaderList {
		headerList = append(headerList, &http_custom_api.HttpKeyValue{
			Id:    p.Id,
			Key:   p.Key,
			Value: p.Value,
		})
	}

	ret := &http_custom_api.ApiItemInfo{
		ApiItemId:   item.ApiItemId,
		ApiItemName: item.ApiItemName,
		GroupId:     item.GroupId,
		Method:      item.Method,
		Url:         item.Url,
		ParamList:   paramList,
		HeaderList:  headerList,
		ContentType: item.ContentType,
		BodyType:    http_custom_api.HTTP_BODY_TYPE(item.BodyType),
	}
	if item.BodyType == uint32(http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_NONE) {
		ret.Body = &http_custom_api.ApiItemInfo_NodyBody{}
	} else if item.BodyType == uint32(http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_TEXT) {
		ret.Body = &http_custom_api.ApiItemInfo_TextBody{
			TextBody: *item.TextBody,
		}
	} else if item.BodyType == uint32(http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_URL_ENCODE) {
		tmpList := []*http_custom_api.HttpKeyValue{}
		for _, p := range item.UrlEncodeBody.ParamList {
			tmpList = append(tmpList, &http_custom_api.HttpKeyValue{
				Id:    p.Id,
				Key:   p.Key,
				Value: p.Value,
			})
		}
		ret.Body = &http_custom_api.ApiItemInfo_UrlEncodeBody{
			UrlEncodeBody: &http_custom_api.UrlEncodeBody{
				ParamList: tmpList,
			},
		}
	} else if item.BodyType == uint32(http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_MULTI_PART) {
		tmpList := []*http_custom_api.MultiPart{}
		for _, p := range item.MultiPartBody.PartList {
			tmpList = append(tmpList, &http_custom_api.MultiPart{
				Id:     p.Id,
				Key:    p.Key,
				Value:  p.Value,
				IsFile: p.IsFile,
			})
		}
		ret.Body = &http_custom_api.ApiItemInfo_MultiPartBody{
			MultiPartBody: &http_custom_api.MultiPartBody{
				PartList: tmpList,
			},
		}
	}
	return ret
}

type _ApiItemDao struct {
	mc *mongo.Collection
}

func newApiItemDao(db *mongo.Database) (*_ApiItemDao, error) {
	mc := db.Collection(db_ns.DB_NS_API_COLLECTION + "custom_item")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"apiCollId", 1}, {"groupId", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_ApiItemDao{mc: mc}, nil
}

func (db *_ApiItemDao) Insert(ctx context.Context, dbItem *ApiItemInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_ApiItemDao) Get(ctx context.Context, apiCollId, apiItemId string) (*ApiItemInfoDbItem, error) {
	retItem := &ApiItemInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"apiCollId": apiCollId, "_id": apiItemId}).Decode(retItem)
	return retItem, err
}

func (db *_ApiItemDao) Exist(ctx context.Context, apiCollId, apiItemId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"apiCollId": apiCollId, "_id": apiItemId})
	return count > 0, err
}

func (db *_ApiItemDao) Remove(ctx context.Context, apiCollId, apiItemId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"apiCollId": apiCollId, "_id": apiItemId})
	return err
}

func (db *_ApiItemDao) RemoveByColl(ctx context.Context, apiCollId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"apiCollId": apiCollId})
	return err
}

func (db *_ApiItemDao) CountByGroup(ctx context.Context, apiCollId, groupId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"apiCollId": apiCollId, "groupId": groupId})
	return uint32(count), err
}

func (db *_ApiItemDao) Update(ctx context.Context, dbItem *ApiItemInfoDbItem) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"apiCollId": dbItem.ApiCollId, "_id": dbItem.ApiItemId}, bson.M{"$set": dbItem})
	return err
}

func (db *_ApiItemDao) List(ctx context.Context, apiCollId string, filterByGroupId bool, groupId string) ([]*ApiItemInfoDbItem, error) {
	query := bson.M{"apiCollId": apiCollId}
	if filterByGroupId {
		query["groupId"] = groupId
	}
	cursor, err := db.mc.Find(ctx, query, options.Find().SetSort(bson.M{"url": 1}))
	if err != nil {
		return nil, err
	}
	retList := []*ApiItemInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}
